package main

/*
%T 类型占位符
%v 值占位符
%p 地址（指针）占位符，只有地址才能替换%p
&value 对值取地址
*addr 对地址取值
**int 指向int型指针的指针
作用：函数传参时，传递指针叫引用传递，值传递是拷贝式的，对被传参数的修改是不会改变本体的，想要改变本体只能是引用传递
*/

import "fmt"

//指针就是地址
//&value 对值取地址
//*ptr 对地址取值
func main041() {

	//声明变量a时，系统开辟了一块内存【地址】，里面存的【值】是123
	var a int = 123
	fmt.Printf("a的类型是%T\n", a)//int
	fmt.Printf("a的值是%v\n", a)//123
	fmt.Printf("a的地址是%p\n", &a)//0x...

	//&a取变量a的地址
	aPointer := &a
	fmt.Printf("aPointer的类型是%T\n",aPointer)//*int

	//将aPointer指向的地址中的值修改为456
	*aPointer = 456
	fmt.Println("*aPointer=",*aPointer)//456
	//a的值就变成了456
	fmt.Println("a=",a)
}

//先定义原始变量，修改其指针中的值，会直接改变原变量
//指针如果没有重新赋值，永远指向同一块地址
func main0422() {

	//系统给x分配了内存
	var x = 456
	fmt.Println(x)//456

	//定义整型指针（存储整型数据的地址）
	//默认赋值为空<nil>
	var xPtr *int
	fmt.Println("xPtr=", xPtr)//nil

	//aPtr指向x的地址
	xPtr = &x

	//将xPtr指向的地址中的值修改为789
	*xPtr = 789

	fmt.Println(x)         //789
	fmt.Println(xPtr)      //0xc042052080
	fmt.Println(&x)        //0xc042052080
	fmt.Println(*xPtr)     //789
	fmt.Println(*xPtr == x) //true
	fmt.Println(xPtr == &x) //true

	var y = 456
	*xPtr = y
	fmt.Println(x)          //456
	fmt.Println(xPtr)       //没有变
	fmt.Println(&x)         //没有变
	fmt.Println(*xPtr)      //456
	fmt.Println(*xPtr == y) //true
	fmt.Println(x == y)     //true
	fmt.Println(&x == &y)   //false
	fmt.Println(xPtr == &y) //false

	//xPtr指向y的地址
	xPtr = &y
	y = 789
	fmt.Println(x)          //456
	fmt.Println(y)          //789
	fmt.Println(*xPtr)      //789
	fmt.Println(&x == xPtr) //false
}

//指针是严格检测数据类型的
func main0433() {
	var x = 123
	var intPtr *int
	intPtr = &x
	fmt.Println(intPtr, *intPtr) //0x...,123

	//var y = "你妹"
	//intPtr = &y//编译错误，【整型指针】无法赋值为【字符串的地址】

}

//指针的指针
func main() {
	var x = 123
	var mPtr *int = &x
	//var mmp **int
	mmPtr := &mPtr
	fmt.Println(mmPtr)//0xc042072018
	fmt.Printf("mmPtr的类型是%T\n",mmPtr)//mmPtr的类型是**int

	//打印x的值
	fmt.Println(*mPtr)//123
	fmt.Println(*(*mmPtr))//123
	fmt.Println(**mmPtr)//123
}
